package cn.jetpiece.cloud.dict.app.modular.dict.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.jetpiece.cloud.core.page.PageFactory;
import cn.jetpiece.cloud.core.query.QueryGenerator;
import cn.jetpiece.cloud.core.util.HttpContext;
import cn.jetpiece.cloud.core.util.ResultWrapperUtil;
import cn.jetpiece.cloud.core.util.SqlInjectionUtil;
import cn.jetpiece.cloud.dict.api.DictApi;
import cn.jetpiece.cloud.dict.api.model.params.CreateDictParam;
import cn.jetpiece.cloud.dict.api.model.params.UpdateDictParam;
import cn.jetpiece.cloud.dict.api.model.query.DictQuery;
import cn.jetpiece.cloud.dict.api.model.result.DictResult;
import cn.jetpiece.cloud.dict.api.model.result.DictTreeResult;
import cn.jetpiece.cloud.dict.app.modular.dict.entity.Dict;
import cn.jetpiece.cloud.dict.app.modular.dict.mapper.DictMapper;
import cn.jetpiece.cloud.dict.app.modular.dict.service.IDictService;
import cn.jetpiece.cloud.model.model.*;
import cn.jetpiece.cloud.model.page.PageResult;
import cn.jetpiece.cloud.model.response.Result;
import cn.jetpiece.cloud.redis.contants.CacheConstant;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author hancp
 * @version 1.0
 * @description: 字典表 控制器
 * @date 2021/12/6 11:20
 */
@RestController
@Slf4j
public class DictController implements DictApi {

    @Autowired
    public RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private IDictService dictService;


    /**
     * @param sysDictQuery
     * @return
     */
    @Override
    public Result<PageResult<DictResult>> queryPageList(DictQuery sysDictQuery) {
        Dict sysDict = BeanUtil.toBean(sysDictQuery, Dict.class);
        QueryWrapper<Dict> queryWrapper = QueryGenerator.initQueryWrapper(sysDict, HttpContext.getRequestParameters());
        Page<Dict> page = PageFactory.defaultPage();
        IPage<Dict> pageList = dictService.page(page, queryWrapper);
        return Result.OK(ResultWrapperUtil.wrap(DictResult.class, pageList));
    }

    /**
     * 获取树形字典数据
     *
     * @param sysDictQuery
     * @return
     */
    @Override
    public Result<List<DictTreeResult>> listTree(DictQuery sysDictQuery) {
        Result<List<DictTreeResult>> result = new Result<>();
        Dict sysDict = BeanUtil.toBean(sysDictQuery, Dict.class);
        LambdaQueryWrapper<Dict> query = new LambdaQueryWrapper<>();
        // 构造查询条件
        String dictName = sysDict.getDictName();
        if (StrUtil.isNotEmpty(dictName)) {
            query.like(true, Dict::getDictName, dictName);
        }
        query.orderByDesc(true, Dict::getCreateTime);
        List<Dict> list = dictService.list(query);
        List<SysDictTree> treeList = new ArrayList<>();
        for (Dict node : list) {
            SysDictTree sysDictTree = new SysDictTree();
            sysDictTree.setId(node.getId());
            sysDictTree.setKey(node.getId() + "");
            sysDictTree.setTitle(node.getDictName());
            sysDictTree.setDictCode(node.getDictCode());
            sysDictTree.setDescription(node.getDescription());
            sysDictTree.setDelFlag(node.getDelFlag());
            sysDictTree.setType(node.getType());
            treeList.add(sysDictTree);
        }
        result.setSuccess(true);
        result.setResult(BeanUtil.copyToList(treeList, DictTreeResult.class));
        return result;
    }

    /**
     * 获取字典数据
     *
     * @param dictCode 字典code
     * @param dictCode 表名,文本字段,code字段  | 举例：sys_user,realname,id
     * @return
     */
    @Override
    public Result<List<DictModel>> listDictItems(@PathVariable String dictCode) {
        log.info(" dictCode : " + dictCode);
        Result<List<DictModel>> result = new Result<List<DictModel>>();
        List<DictModel> ls = null;
        try {
            if (dictCode.indexOf(",") != -1) {
                //关联表字典（举例：sys_user,realname,id）
                String[] params = dictCode.split(",");

                if (params.length < 3) {
                    result.error500("字典Code格式不正确！");
                    return result;
                }
                //SQL注入校验（只限制非法串改数据库）
                final String[] sqlInjCheck = {params[0], params[1], params[2]};
                SqlInjectionUtil.filterContent(sqlInjCheck);

                if (params.length == 4) {
                    //SQL注入校验（查询条件SQL 特殊check，此方法仅供此处使用）
                    SqlInjectionUtil.specialFilterContent(params[3]);
                    ls = dictService.queryTableDictItemsByCodeAndFilter(params[0], params[1], params[2], params[3]);
                } else if (params.length == 3) {
                    ls = dictService.queryTableDictItemsByCode(params[0], params[1], params[2]);
                } else {
                    result.error500("字典Code格式不正确！");
                    return result;
                }
            } else {
                //字典表
                ls = dictService.queryDictItemsByCode(dictCode);
            }

            result.setSuccess(true);
            result.setResult(ls);
            log.debug(result.toString());
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            result.error500("操作失败");
            return result;
        }

        return result;
    }

    /**
     * 获取全部字典数据
     */
    @Override
    public Result<Map<String, List<DictModel>>> listAllDictItems() {
        Result<Map<String, List<DictModel>>> result = new Result<>();
        result.setResult(dictService.queryAllDictItems());
        result.setSuccess(true);
        return result;
    }

    /**
     * 获取字典Text
     *
     * @param dictCode
     * @return
     */
    @Override
    public Result<String> getDictText(String dictCode, String key) {
        log.info(" dictCode : " + dictCode);
        Result<String> result = new Result<>();
        String text;
        try {
            text = dictService.queryDictTextByKey(dictCode, key);
            result.setSuccess(true);
            result.setResult(text);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            result.error500("操作失败");
            return result;
        }
        return result;
    }

    /**
     * 大数据量的字典表 走异步加载  即前端输入内容过滤数据
     *
     * @param dictCode
     * @return
     */
    @Override
    public Result<List<DictModel>> listByDictCode(@PathVariable String dictCode, @RequestParam(name = "keyword") String keyword,
                                                  @RequestParam(value = "pageSize", required = false) Integer pageSize) {
        log.info(" 加载字典表数据,加载关键字: " + keyword);
        Result<List<DictModel>> result = new Result<>();
        List<DictModel> ls = null;
        try {
            if (dictCode.indexOf(",") != -1) {
                String[] params = dictCode.split(",");
                if (params.length != 3) {
                    result.error500("字典Code格式不正确！");
                    return result;
                }
                if (pageSize != null) {
                    ls = dictService.queryLittleTableDictItems(params[0], params[1], params[2], keyword, pageSize);
                } else {
                    ls = dictService.queryTableDictItems(params[0], params[1], params[2], keyword);
                }
                result.setSuccess(true);
                result.setResult(ls);
                log.info(result.toString());
            } else {
                result.error500("字典Code格式不正确！");
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            result.error500("操作失败");
            return result;
        }

        return result;
    }

    /**
     * 根据字典code加载字典text 返回
     */
    @Override
    public Result<List<String>> listDictText(@PathVariable String dictCode, @RequestParam(name = "key") String keys, @RequestParam(value = "sign", required = false) String sign) {
        Result<List<String>> result = new Result<>();
        try {
            if (dictCode.indexOf(",") != -1) {
                String[] params = dictCode.split(",");
                if (params.length != 3) {
                    result.error500("字典Code格式不正确！");
                    return result;
                }
                List<String> texts = dictService.queryTableDictByKeys(params[0], params[1], params[2], keys);

                result.setSuccess(true);
                result.setResult(texts);
                log.info(result.toString());
            } else {
                result.error500("字典Code格式不正确！");
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            result.error500("操作失败");
            return result;
        }

        return result;
    }

    /**
     * 根据表名——显示字段-存储字段 pid 加载树形数据
     */
    @Override
    public Result<List<TreeSelectResult>> listTreeData(@RequestParam(name = "pid") String pid, @RequestParam(name = "pidField") String pidField,
                                                       @RequestParam(name = "tableName") String tbname,
                                                       @RequestParam(name = "text") String text,
                                                       @RequestParam(name = "code") String code,
                                                       @RequestParam(name = "hasChildField") String hasChildField,
                                                       @RequestParam(name = "condition") String condition,
                                                       @RequestParam(value = "sign", required = false) String sign) {
        Result<List<TreeSelectResult>> result = new Result<>();
        Map<String, String> query = null;
        if (StrUtil.isNotEmpty(condition)) {
            query = JSON.parseObject(condition, Map.class);
        }
        // SQL注入漏洞 sign签名校验(表名,label字段,val字段,条件)
        String dictCode = tbname + "," + text + "," + code + "," + condition;
        SqlInjectionUtil.filterContent(dictCode);
        List<TreeSelectModel> ls = dictService.queryTreeList(query, tbname, text, code, pidField, pid, hasChildField);
        result.setSuccess(true);
        result.setResult(BeanUtil.copyToList(ls, TreeSelectResult.class));
        return result;
    }

    /**
     * 【APP接口】根据字典配置查询表字典数据
     *
     * @param query
     * @return
     */
    @Override
    public Result<List<DictModel>> listTableData(TableDictQuery query) {
        Result<List<DictModel>> res = new Result<>();
        // SQL注入漏洞 sign签名校验
        String dictCode = query.getTable() + "," + query.getText() + "," + query.getCode();
        SqlInjectionUtil.filterContent(dictCode);
        List<DictModel> ls = this.dictService.queryDictTablePageList(query);
        res.setResult(ls);
        res.setSuccess(true);
        return res;
    }

    /**
     * 新增
     *
     * @param sysDictParam
     * @return
     */
    //@RequiresRoles({"admin"})
    @Override
    public Result<DictResult> add(@RequestBody CreateDictParam sysDictParam) {
        Result<DictResult> result = new Result<>();
        try {
            sysDictParam.setCreateTime(new Date());
            dictService.save(BeanUtil.toBean(sysDictParam, Dict.class));
            result.success("保存成功！");
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            result.error500("操作失败");
        }
        return result;
    }

    /**
     * 编辑
     *
     * @param sysDictParam
     * @return
     */
    //@RequiresRoles({"admin"})
    @Override
    public Result<DictResult> edit(@RequestBody UpdateDictParam sysDictParam) {
        Result<DictResult> result = new Result<>();
        Dict sysdict = dictService.getById(sysDictParam.getId());
        if (sysdict == null) {
            result.error500("未找到对应实体");
        } else {
            sysDictParam.setUpdateTime(new Date());
            boolean ok = dictService.updateById(BeanUtil.toBean(sysDictParam, Dict.class));
            if (ok) {
                result.success("编辑成功!");
            }
        }
        return result;
    }

    /**
     * 删除
     *
     * @param ids
     * @return
     */
    //@RequiresRoles({"admin"})
    @Override
    @CacheEvict(value = CacheConstant.SYS_DICT_CACHE, allEntries = true)
    public Result<DictResult> delete(String ids) {
        Result<DictResult> result = new Result<>();
        if (StrUtil.isEmpty(ids)) {
            result.error500("参数不识别！");
        } else {
            List<Long> idList = Arrays.stream(ids.split(",")).map(a -> Long.valueOf(a)).collect(Collectors.toList());
            boolean ok = dictService.removeByIds(idList);
            if (ok) {
                result.success("删除成功!");
            } else {
                result.error500("删除失败!");
            }
        }
        return result;
    }

    /**
     * 刷新缓存
     *
     * @return
     */
    @Override
    public Result<String> refreshCache() {
        Result<String> result = new Result<>();
        //清空字典缓存
        Set keys = redisTemplate.keys(CacheConstant.SYS_DICT_CACHE + "*");
        Set keys2 = redisTemplate.keys(CacheConstant.SYS_DICT_TABLE_CACHE + "*");
        Set keys3 = redisTemplate.keys(CacheConstant.SYS_DEPARTS_CACHE + "*");
        Set keys4 = redisTemplate.keys(CacheConstant.SYS_DEPART_IDS_CACHE + "*");
        redisTemplate.delete(keys);
        redisTemplate.delete(keys2);
        redisTemplate.delete(keys3);
        redisTemplate.delete(keys4);
        return result.success("刷新缓存");
    }


    /**
     * 查询被删除的列表
     *
     * @return
     */
    @Override
    public Result<List<DictResult>> deleteList() {
        Result<List<DictResult>> result = new Result<>();
        List<Dict> list = this.dictService.queryDeleteList();
        result.setSuccess(true);
        result.setResult(BeanUtil.copyToList(list, DictResult.class));
        return result;
    }

    /**
     * 物理删除
     *
     * @param id
     * @return
     */
    @Override
    public Result<String> deletePhysic(@PathVariable String id) {
        Result<String> result = new Result<>();
        try {
            dictService.deleteOneDictPhysically(id);
            return result.success("删除成功!");
        } catch (Exception e) {
            e.printStackTrace();
            return result.error500("删除失败!");
        }
    }

    /**
     * 取回
     *
     * @param id
     * @return
     */
    @Override
    public Result<String> back(@PathVariable String id) {
        Result<String> result = new Result<>();
        try {
            dictService.updateDictDelFlag(0, id);
            return result.success("操作成功!");
        } catch (Exception e) {
            e.printStackTrace();
            return result.error500("操作失败!");
        }
    }

    /**
     *  根据多个字典code查询多个字典项
     * @param dictCodeList
     * @return key = dictCode ； value=对应的字典项
     */
    @Override
   public Result<Map<String, List<DictModel>>> getManyDictItems(List<String> dictCodeList){
       Result<Map<String,List<DictModel>>> result = new Result<>();
       try{
           result.setResult(dictService.queryDictItemsByCodeList(dictCodeList));
           result.setSuccess(true);
           return result;
       }catch (Exception e) {
           e.printStackTrace();
           return result.error500("操作失败!");
       }
   }

    @Override
    public Result<List<DictModel>> loadDictOrderByValue(String dictCode, String keyword, String sign, Integer pageSize) {
        // 首次查询查出来用户选中的值，并且不分页
        Result<List<DictModel>> firstRes = this.loadDict(dictCode, keyword, sign, null);
        if (!firstRes.isSuccess()) {
            return firstRes;
        }
        // 然后再查询出第一页的数据
        Result<List<DictModel>> result = this.loadDict(dictCode, "", sign, pageSize);
        if (!result.isSuccess()) {
            return result;
        }
        // 合并两次查询的数据
        List<DictModel> firstList = firstRes.getResult();
        List<DictModel> list = result.getResult();
        for (DictModel firstItem : firstList) {
            // anyMatch 表示：判断的条件里，任意一个元素匹配成功，返回true
            // allMatch 表示：判断条件里的元素，所有的都匹配成功，返回true
            // noneMatch 跟 allMatch 相反，表示：判断条件里的元素，所有的都匹配失败，返回true
            boolean none = list.stream().noneMatch(item -> item.getValue().equals(firstItem.getValue()));
            // 当元素不存在时，再添加到集合里
            if (none) {
                list.add(0, firstItem);
            }
        }
        return result;
    }

    @Override
    public Result<List<DictModel>> loadDict(String dictCode, String keyword, String sign, Integer pageSize) {
        log.info(" 加载字典表数据,加载关键字: "+ keyword);
        Result<List<DictModel>> result = new Result<List<DictModel>>();
        try {
            List<DictModel> ls = dictService.loadDict(dictCode, keyword, pageSize);
            if (ls == null) {
                result.error500("字典Code格式不正确！");
                return result;
            }
            result.setSuccess(true);
            result.setResult(ls);
            log.info(result.toString());
            return result;
        } catch (Exception e) {
            log.error(e.getMessage(),e);
            result.error500("操作失败");
            return result;
        }
    }

}
